#include <iostream>
#include <string>
#include "Log.hpp"
#include "Socket.hpp"
#include <memory>
#include <cstring>
#include <cerrno>
#include <ctime>
#include <poll.h>
using namespace std;
const int num = 1024;


class PollServer {
public :
    PollServer(uint16_t port) 
        :_listensocket(new TcpSocket)
        ,_port(port)
        ,_isrunning(false)
        ,_num(num)
    {

    }

    void Init() {
        // 创建一特监听套接字
        _listensocket->BuildListenSocketMethod(_port, default_backlog);
        _rfds = new struct pollfd[_num];
        for (int i = 0; i < _num; i++) {
            _rfds[i].fd = -1;
            _rfds[i].events = 0;
            _rfds[i].revents = 0;
        }
        _rfds[0].fd = _listensocket->GetSockFd();
        _rfds[0].events |= POLLIN;
    }

    void Handler() {
        for (int i = 0; i < _num; i++) {
            if (_rfds[i].fd == -1) {
                continue;
            }
            if (_rfds[i].revents & POLLIN) { // 说明有读事件就绪
                if (_rfds[i].fd == _listensocket->GetSockFd()) {
                    lg.LogMessage(Info, "get a new link!");
                    string clientip;
                    uint16_t clientport;
                    Socket* newsocket = _listensocket->AcceptSocket(&clientip, &clientport);
                    if (newsocket) {
                        // 获取一个新链接
                        // 将新链接加入到_rfds_array
                        int pos = 0;
                        while (pos < _num) {
                            if (_rfds[pos].fd == -1) {
                                _rfds[pos].fd = newsocket->GetSockFd();
                                _rfds[pos].events |= POLLIN;
                                lg.LogMessage(Info, "get a new link fd is: %d", newsocket->GetSockFd());
                                break;
                            }
                            pos++;
                        }
                        if (pos == num) {
                            // 说明当前可以管理的文件描述符已满，已经处理不了了
                            // 直接关闭
                            newsocket->CloseSockFd();
                            delete newsocket;
                        }
                    } else {
                        lg.LogMessage(Error, "link error");
                        continue;       

                    }
                } else {
                    // 收发数据
                    int fd = _rfds[i].fd;
                    char buffer[1024];
                    int n = recv(fd, buffer, sizeof(buffer) - 1, 0);
                    if (n > 0) {
                        pthread_mutex_lock(&mtx);
                        buffer[n] = '\0';
                        cout << "client say# " << buffer << endl;
                        pthread_mutex_unlock(&mtx);
                        string rbuffer = "server echo# 你好啊!\n";
                        n = send(fd, rbuffer.c_str(), rbuffer.size(), 0);
                    } else {
                        // 读取失败，不管为什么，直接关闭
                        close(_rfds[i].fd);
                        _rfds[i].fd = -1;
                        _rfds[i].events = 0;
                        _rfds[i].revents = 0;
                    }
                }
            }
        }

    }

    void Stop() {
        _isrunning = false;
    }

    void Loop() {
        _isrunning = true;
        while (_isrunning) {
            PrintDebug();
            int timeout = -1;
            int n = poll(_rfds, _num, timeout);
            if (n > 0) {
                lg.LogMessage(Info, "已有读事件就绪");
                // 处理读就绪
                Handler();
            } else if (n == 0) {
                // 超时返回
                lg.LogMessage(Info, "poll超时返回");
            } else {
                // select出错了
                lg.LogMessage(Fatal, "poll error! errno: %d, errorstring: %s", errno, strerror(errno));
                break;  
            }

        }

    }

    void PrintDebug() {
        pthread_mutex_lock(&mtx);
        cout << "current fd list: ";
        for (int i = 0; i < _num; i++) {
            if (_rfds[i].fd != -1) {
                cout << _rfds[i].fd << " ";
            }
        }
        cout << endl;
        pthread_mutex_unlock(&mtx);
    }

    ~PollServer() {
        delete [] _rfds;
    }

private :
    unique_ptr<Socket> _listensocket;
    uint16_t _port;
    bool _isrunning;
    struct pollfd* _rfds;
    int _num;
};


